<?php
/* 单元测试
*
*
*/

namespace hpnWse\nMvc {

require_once(\hpnWse\fGetWseDiry() . 'hpnWse/nMvc/(0)Mdl.php');

use \hpnWse\stNumUtil;
use \hpnWse\stStrUtil;
use \hpnWse\stRgxUtil;
use \hpnWse\stAryUtil;
use \hpnWse\stObjUtil;
use \hpnWse\stFctnUtil;

/// 过滤器验证器管理器
class stFvMgr
{
	/// 公共验证器，内部使用
	public static $c_Rqrd = null;
	public static $c_SameType = null;

	// 获取过滤器验证器全类型名
	public static function eGetFvFullTpnm($a_IsFltr, $a_Tpnm)
	{
		return '\\hpnWse\\nMvc\\' . ($a_IsFltr ? 'nFltr\\' : 'nVldtr\\') . $a_Tpnm;
	}

	// 反序列化（过滤器和验证器）
	public static function eDsrlz($a_Cmn, $a_FltrsJson, $a_VldtrsJson)
	{
		$l_FldFltrs = &$a_Cmn->e_Fltrs;
		$l_FldVldtrs = &$a_Cmn->e_Vldtrs;
		$i; $l_Len; 
		$l_Etr; $l_Vldtr; $l_Fltr;
		$l_Len = \hpnWse\fBool($a_FltrsJson) ? count($a_FltrsJson) : 0;
		for ($i = 0; $i<$l_Len; ++$i)
		{
			$l_Etr = $a_FltrsJson[$i];
			$l_fCtor = self::eGetFvFullTpnm(true, $l_Etr['c_Tpnm']);
			if (! class_exists($l_fCtor))	// 遇到不支持的类型，跳过，但给出警告
			{
				throw new \Exception(('过滤器“' . $l_Etr['c_Tpnm'] . '”没有注册，将被忽略！'), -1);
			//	continue;
			}

			$l_Fltr = new $l_fCtor();	// 无需提供任何参数，接着会调用vcLoad
			$l_Fltr->vcLoad($l_Etr);
			$l_FldFltrs[] = ($l_Fltr);
		}
		$l_Len = \hpnWse\fBool($a_VldtrsJson) ? count($a_VldtrsJson) : 0;
		for ($i = 0; $i<$l_Len; ++$i)
		{
			$l_Etr = $a_VldtrsJson[$i];
			$l_fCtor = self::eGetFvFullTpnm(false, $l_Etr['c_Tpnm']);
			if (! class_exists($l_fCtor))	// 遇到不支持的类型，跳过，但给出警告
			{
				throw new \Exception(('验证器“' . $l_Etr['c_Tpnm'] . '”没有注册，将被忽略！'), -1);
			//	continue;
			}

			$l_Vldtr = new $l_fCtor();	// 无需提供任何参数，接着会调用vcLoad
			$l_Vldtr->vcLoad($l_Etr);
			$l_FldVldtrs[] = ($l_Vldtr);
		}
	}

	// 序列化（过滤器和验证器）
	public static function eSrlz(&$a_Json, $a_Fltrs, $a_Vldtrs)
	{
		$i; $l_Len; $l_Etr; $l_Jsons;
		$l_Len = count($a_Fltrs);
		if ($l_Len > 0)
		{
			$a_Json['Wse_Fltrs'] = array();
			$l_Jsons = &$a_Json['Wse_Fltrs'];
		}
		for ($i = 0; $i<$l_Len; ++$i)
		{
			$l_Etr = array();
			$a_Fltrs[$i]->vcSave($l_Etr);
			$l_Jsons[] = $l_Etr;
		}
		$l_Len = count($a_Vldtrs);
		if ($l_Len > 0)
		{
			$a_Json['Wse_Vldtrs'] = array();
			$l_Jsons = &$a_Json['Wse_Vldtrs'];
		}
		for ($i = 0; $i<$l_Len; ++$i)
		{
			$l_Etr = array();
			$a_Vldtrs[$i]->vcSave($l_Etr);
			$l_Jsons[] = $l_Etr;
		}
	}

	/// 将过滤器验证器转成JSON字符串
	public static function cToJsonStr($a_FvIstn)
	{
		$l_Json = array();
		$a_FvIstn->vcSave($l_Json);
		return \hpnWse\stObjUtil::cEcdJson($l_Json);
	}
}

} // namespace hpnWse\nMvc


//================ 各种内建过滤器

namespace hpnWse\nMvc\nFltr {

use \hpnWse\stNumUtil;
use \hpnWse\stStrUtil;
use \hpnWse\stRgxUtil;
use \hpnWse\stAryUtil;
use \hpnWse\stObjUtil;
use \hpnWse\stFctnUtil;

use \hpnWse\nMvc;
use \hpnWse\nMvc\stFvMgr;

/// 过滤器
class atFltr
{
	public $c_Dsab;

	public function __construct()
	{
		$this->c_Dsab = false;
	}

	/// 运行
	/// a_Mdl：tMdl，模型
	/// a_Key：String，键
	/// a_Val：基元值$tMdl$Null，将被验证的值
	/// 返回：Boolean$Number$String，过滤结果
	public function vcRun($a_Mdl, $a_Key, $a_Val)
	{
		return $this;
	}

	/// 加载
	/// a_Json：Object，属性对应本过滤器的参数
	public function vcLoad($a_Json)
	{
		$this->c_Dsab = stObjUtil::cFchPpty($a_Json, 'c_Dsab', false);
		return $this;
	}

	/// 保存
	/// a_Json：Object，属性对应本过滤器的参数
	public function vcSave(&$a_Json)
	{
		$a_Json['c_Tpnm'] = (stObjUtil::cGetTpnm($this)); // 类型名
		if ($this->c_Dsab) { $a_Json['c_Dsab'] = true; }
		return $this;
	}
}

/// 修剪，用于String
class tTrim extends atFltr
{
	public function __construct()
	{
		parent::__construct();
	}

	public function vcRun($a_Mdl, $a_Key, $a_Val)
	{
		return trim(strval($a_Val));
	}
}

/// 擦除空白，用于String
class tErsWhtSpc extends atFltr
{
	public function __construct()
	{
		parent::__construct();
	}

	public function vcRun($a_Mdl, $a_Key, $a_Val)
	{
		return preg_replace('/\\s/', '', strval($a_Val));
	}	
}

/// 融合空白，用于String
class tMgeWhtSpc extends atFltr
{
	public function __construct()
	{
		parent::__construct();
	}

	public function vcRun($a_Mdl, $a_Key, $a_Val)
	{
		return preg_replace('/\\s+/', ' ', strval($a_Val));
	}	
}

/// 排序CSV，用于String
class tSortCsv extends atFltr
{
	public function __construct()
	{
		parent::__construct();
	}

	public function vcRun($a_Mdl, $a_Key, $a_Val)
	{
		if (! is_string($a_Val)) // 非字符串时原样返回
		{ return $a_Val; }

		$l_VA = explode(',', $a_Val);
		sort($l_VA, SORT_STRING);
		return implode(',', $l_VA);
	}	
}

/// 去重CSV格式的输入值，同时保持原有顺序
class tRmvDuplCsv extends atFltr
{
	public function __construct()
	{
		parent::__construct();
	}

	public function vcRun($a_Mdl, $a_Key, $a_Val)
	{
		if (! is_string($a_Val)) // 非字符串时原样返回
		{ return $a_Val; }

		$l_VA = explode(',', $a_Val);
		$l_Vals = array();
		for ($i=0; $i<count($l_VA); ++$i)
		{ stAryUtil::cPushIfNonExi($l_Vals, $l_VA[$i]); }
		return implode(',', $l_Vals);
	}	
}

/// 截断数字
/// a_Min，a_Max：Number，区间范围
/// a_Int：Boolean，取整？
class tClmNum extends atFltr
{
	public $c_Min;
	public $c_Max;
	public $c_Int;

	public function __construct($a_Min = 0, $a_Max = PHP_INT_MAX, $a_Int = false)
	{
		parent::__construct();

		$this->c_Min = $a_Min;
		$this->c_Max = $a_Max;
		$this->c_Int = $a_Int;
	}

	/// 运行
	public function vcRun($a_Mdl, $a_Key, $a_Val)
	{
		return stNumUtil::cClmOnNum($this->c_Int ? round($a_Val) : $a_Val, $this->c_Min, $this->c_Max);
	}

	/// 加载
	public function vcLoad($a_Json)
	{
		parent::vcLoad($a_Json);
		$this->c_Min = $a_Json['c_Min'];
		$this->c_Max = $a_Json['c_Max'];
		$this->c_Int = $a_Json['c_Int'];
		return $this;
	}

	/// 保存
	public function vcSave(&$a_Json)
	{
		parent::vcSave($a_Json);
		$a_Json['c_Min'] = $this->c_Min;
		$a_Json['c_Max'] = $this->c_Max;
		$a_Json['c_Int'] = $this->c_Int;
		return $this;
	}
}

///【tClmIdx】主要为前端使用

} // hpnWse\nMvc\nFltr

namespace hpnWse\nMvc\nVldtr {

use \hpnWse\stNumUtil;
use \hpnWse\stStrUtil;
use \hpnWse\stRgxUtil;
use \hpnWse\stAryUtil;
use \hpnWse\stObjUtil;
use \hpnWse\stFctnUtil;

use \hpnWse\nMvc;
use \hpnWse\nMvc\stFvMgr;

/// 验证器
class atVldtr
{
	public $c_Info;
	public $c_Dsab;

	public function __construct($a_Info = '')
	{
		$this->c_Info = $a_Info;
		$this->c_Dsab = false;
	}

	/// 信息
	/// a_Info：若不传，或传undefined或null，则不做更新
	public function cTheInfo($a_Info = null)
	{
		$l_AgmAmt = func_num_args();
		return ($l_AgmAmt < 1) ? $this->c_Info : ($this->c_Info = $a_Info);
	}

	/// 生成信息
	public function vcGnrtInfo($a_Mdl, $a_Key, $a_Val)
	{
		$l_Map = array();
		$this->vcSave($l_Map);
		$l_Map["a_Mdl"] = \hpnWse\stObjUtil::cGetTpnm($a_Mdl); // 默认显示类名
		$l_Map["a_Key"] = strval($a_Key);
		$l_Map["a_Val"] = strval($a_Val);
		return \hpnWse\stStrUtil::cRplcPlchd($this->c_Info, $l_Map);
	}

	/// 运行
	/// a_Mdl：tMdl，模型
	/// a_Key：String，键
	/// a_Val：基元值$tMdl$Null，将被验证的值
	/// 返回：Boolean，成败
	public function vcRun($a_Mdl, $a_Key, $a_Val)
	{ }

	/// 加载
	/// a_Json：Object，属性对应本验证器的参数
	public function vcLoad($a_Json)
	{
		$this->c_Info = stObjUtil::cFchPpty($a_Json, 'c_Info', $this->c_Info);
		$this->c_Dsab = stObjUtil::cFchPpty($a_Json, 'c_Dsab', false);
		return $this;
	}

	/// 保存
	/// a_Json：Object，属性对应本验证器的参数
	public function vcSave(&$a_Json)
	{
		$a_Json['c_Tpnm'] = stObjUtil::cExtrTpnm(stObjUtil::cGetFullTpnm($this)); // 类型名
		$a_Json['c_Info'] = \hpnWse\fV1OrV2($this->c_Info, '');
		if ($this->c_Dsab) { $a_Json['c_Dsab'] = true; }
		return $this;
	}
}

/// 必填
class tRqrd extends atVldtr
{
	public function __construct($a_Info = '这一项还没有填写。')
	{
		parent::__construct($a_Info);
	}

	/// 运行
	public function vcRun($a_Mdl, $a_Key, $a_Val)
	{
		return ! \hpnWse\fIsUdfnOrNullOrEstr($a_Val);
	}
}
stFvMgr::$c_Rqrd = new tRqrd();

/// 必填，【注意】本验证器仅由tMdl内部使用！
class tSameType extends atVldtr
{
	public function __construct($a_Info = '无效的数据类型。')
	{
		parent::__construct($a_Info);
	}

	/// 运行
	public function vcRun($a_Mdl, $a_Key, $a_Val)
	{
		throw new \Exception('本验证器仅由tMdl内部使用！', -1);
	//	return ! nWse.fIsUdfnOrNullOrEstr(a_Val);
	}
}
stFvMgr::$c_SameType = new tSameType();

/// 字符串长度范围
/// a_Min，a_Max：Number，范围
/// a_Info：String，信息
class tStrLenRge extends atVldtr
{
	public $c_Min;
	public $c_Max;

	public function __construct($a_Min = 0, $a_Max = PHP_INT_MAX, 
								$a_Info = '字符个数不在有效范围内。')
	{
		parent::__construct($a_Info);

		$this->c_Min = $a_Min;
		$this->c_Max = $a_Max;
	//	$this->cFixInfoByPpty();
	}

	/// 运行
	public function vcRun($a_Mdl, $a_Key, $a_Val)
	{
		$l_Len = stStrUtil::cGetLen($a_Val);
		return ($this->c_Min <= $l_Len) && ($l_Len <= $this->c_Max);
	}

	/// 加载
	public function vcLoad($a_Json)
	{
		parent::vcLoad($a_Json);
		$this->c_Min = $a_Json['c_Min'];
		$this->c_Max = $a_Json['c_Max'];
		return $this;
	}

	/// 保存
	public function vcSave(&$a_Json)
	{
		parent::vcSave($a_Json);
		$a_Json['c_Min'] = $this->c_Min;
		$a_Json['c_Max'] = $this->c_Max;
		return $this;
	}
}

/// 字符串模式
/// a_Rgx：RegExp，正则表达式
/// a_Info：String，信息
class tStrPtn extends atVldtr
{
	public $c_Rgx;

	public function __construct($a_Rgx = '/[\\s\\S]/',
								$a_Info = '无效的数据格式。')
	{
		parent::__construct($a_Info);

		$this->c_Rgx = $a_Rgx;
	}

	/// 运行
	public function vcRun($a_Mdl, $a_Key, $a_Val)
	{
		return stRgxUtil::cTest($this->c_Rgx, $a_Val);
	}

	/// 加载
	public function vcLoad($a_Json)
	{
		parent::vcLoad($a_Json);
		$this->c_Rgx = $a_Json['c_Rgx'];
		return $this;
	}

	/// 保存
	public function vcSave(&$a_Json)
	{
		parent::vcSave($a_Json);
		$a_Json['c_Rgx'] = $this->c_Rgx;
		return $this;
	}
}

/// 相等
/// a_Val：String，值
/// a_Info：String，信息
class tEq extends atVldtr
{
	public $c_Val;

	public function __construct($a_Val = '',
								$a_Info = '错误的输入值。')
	{
		parent::__construct($a_Info);

		$this->c_Val = $a_Val;
	}

	/// 运行
	public function vcRun($a_Mdl, $a_Key, $a_Val)
	{
		return ($a_Val === $this->c_Val);
	}

	/// 加载
	public function vcLoad($a_Json)
	{
		parent::vcLoad($a_Json);
		$this->c_Val = $a_Json['c_Val'];
		return $this;
	}

	/// 保存
	public function vcSave(&$a_Json)
	{
		parent::vcSave($a_Json);
		$a_Json['c_Val'] = $this->c_Val;
		return $this;
	}
}

/// 与另一字段值相同
/// a_Key：String，键
/// a_Info：String，信息
class tSameAsFld extends atVldtr
{
	public $c_Key;

	public function __construct($a_Key = '',
								$a_Info = '两次输入的内容不同。')
	{
		parent::__construct($a_Info);

		$this->c_Key = $a_Key;
	}

	/// 运行
	public function vcRun($a_Mdl, $a_Key, $a_Val)
	{
		return ($a_Val === $a_Mdl->cReadFld($this->c_Key));
	}

	/// 加载
	public function vcLoad($a_Json)
	{
		parent::vcLoad($a_Json);
		$this->c_Key = $a_Json['c_Key'];
		return $this;
	}

	/// 保存
	public function vcSave(&$a_Json)
	{
		parent::vcSave($a_Json);
		$a_Json['c_Key'] = $this->c_Key;
		return $this;
	}
}

/// 元素数量范围，用于字段集为数组的模型
/// a_Min，a_Max：Number，范围
/// a_Info：String，信息
class tElmtAmtRge extends atVldtr
{
	public $c_Min;
	public $c_Max;

	public function __construct($a_Min = 0, $a_Max = PHP_INT_MAX, 
								$a_Info = '元素数量不在有效范围内。')
	{
		parent::__construct($a_Info);

		$this->c_Min = $a_Min;
		$this->c_Max = $a_Max;
	}

	/// 运行
	public function vcRun($a_Mdl, $a_Null, $a_Udfn)
	{
		$l_Amt = $a_Mdl->cGetFldAmt();
		return ($this->c_Min <= $l_Amt) && ($l_Amt <= $this->c_Max);
	}

	/// 加载
	public function vcLoad($a_Json)
	{
		parent::vcLoad($a_Json);
		$this->c_Min = $a_Json['c_Min'];
		$this->c_Max = $a_Json['c_Max'];
		return $this;
	}

	/// 保存
	public function vcSave(&$a_Json)
	{
		parent::vcSave($a_Json);
		$a_Json['c_Min'] = $this->c_Min;
		$a_Json['c_Max'] = $this->c_Max;
		return $this;
	}
}


//========================【添加一些常用的验证器】

function ufRtnIstn($a_Istn, $a_RtnJson)
{
	if (! property_exists($a_Istn, 'i_Json'))
	{
		$a_Istn->i_Json = array();
		$a_Istn->vcSave($a_Istn->i_Json);
	}
	return $a_RtnJson ? \hpnWse\stObjUtil::cEcdJson($a_Istn->i_Json) : $a_Istn;
}

/// 电子邮件
function fEmail($a_RtnJson = false)
{
	static $s_Istn = null;
	if (! $s_Istn)
	{
		$s_Istn = new tStrPtn('/^[a-z0-9_-]+@[a-z0-9]+(?:\\.[a-z0-9]+)+$/', '不是有效的邮箱地址。');
	}
	return ufRtnIstn($s_Istn, $a_RtnJson);
}

/// HTTP URL
function fHttpUrl($a_RtnJson = false)
{
	static $s_Istn = null;
	if (! $s_Istn)
	{
		$s_Istn = new tStrPtn('/^https?:\/\/.+$/', '不是有效的HTTP URL。');
	}
	return ufRtnIstn($s_Istn, $a_RtnJson);
}

/// 手机号（Mobile Phone Number）
function fMpn($a_RtnJson = false)
{
	static $s_Istn = null;
	if (! $s_Istn)
	{
		$s_Istn = new tStrPtn('/^(?:\\+86)?1\\d{10}$/', '不是有效的手机号。');
	}
	return ufRtnIstn($s_Istn, $a_RtnJson);
}

/// 密码相同（Same PassWord）
function fSpw($a_RtnJson = false)
{
	static $s_Istn = null;
	if (! $s_Istn)
	{
		$s_Istn = new tSameAsFld('password', '两次输入的密码不同。');
	}
	return ufRtnIstn($s_Istn, $a_RtnJson);
}

} // hpnWse\nMvc\nVldtr

//////////////////////////////////// OVER ////////////////////////////////////